<script setup>
import SparkMD5 from 'spark-md5'
import { uploadChunk, checkChunk, checkFile, mergeChunk } from '@/api/system'
// 文件上传测试
const FALSE = false
const TRUE = true
const CHRUNK_SIZE = 1024 * 1024 * 5
const MAX_REQUEST_NUM = 4
//单文件上传文件
const customRequest = async (op) => {
  const file = op.fileItem.file
  const chuncks = createChrunk(file)
  const fileMd5 = await calcHash(chuncks)
  console.log('fileMd5', fileMd5)
  await uploadChunks(file.name, chuncks, fileMd5, MAX_REQUEST_NUM)
}
// 创建分片
const createChrunk = (file) => {
  let cur = 0
  let chuncks = []
  while (cur < file.size) {
    const blob = file.slice(cur, cur + CHRUNK_SIZE)
    chuncks.push(blob)
    cur += CHRUNK_SIZE
  }
  return chuncks
}
//计算hash
const calcHash = (chuncks) => {
  const targets = []
  let md5
  const spark = new SparkMD5.ArrayBuffer()
  const fileReader = new FileReader()
  // 为了计算hash更快，截取部分文件片
  chuncks.forEach((chunck, index) => {
    if (index === 0 || index === chuncks.length - 1) {
      targets.push(chunck)
    } else {
      targets.push(chunck.slice(0, 2))
      targets.push(chunck.slice(CHRUNK_SIZE / 2, CHRUNK_SIZE / 2 + 2))
      targets.push(chunck.slice(CHRUNK_SIZE - 2, CHRUNK_SIZE))
    }
  })
  // 好扭比的普绕米斯 令我文件上传爆肥
  // 菜就多练
  return new Promise((resolve, reject) => {
    fileReader.readAsArrayBuffer(new Blob(targets))

    fileReader.onload = (e) => {
      spark.append(e.target.result)
      const md5 = spark.end()
      resolve(md5) // 成功时返回md5值
    }

    fileReader.onerror = (err) => {
      reject(err) // 失败时抛出错误
    }
  })
}
// 分片上传
const uploadChunks = async (fileName, chunks, fileMd5, MAX_REQUEST_NUM = 5) => {
  const formDatas = chunks.map((chunk, index) => {
    const formData = new FormData()
    formData.append('fileName', fileName)
    formData.append('fileMd5', fileMd5)
    formData.append('chunkMd5', `${fileMd5}-${index}`)
    formData.append('chunk', chunk)
    return formData
  })

  let index = 0
  const activePromises = []
  let process = ((index / formDatas.length) * 100).toFixed(2)
  console.log('进度:', process + '%')
  const uploadNext = async () => {
    if (index >= formDatas.length) {
      // 所有分片都已上传
      await Promise.all(activePromises) // 等待所有剩余的活动 Promise 完成（理论上应该是空的）
      // 合并分片
      const mergeChunkDto = { fileName, fileMd5 }
      await mergeChunk(mergeChunkDto)
      return
    }

    // 开始上传下一个分片
    const formData = formDatas[index]
    const promise = uploadChunk(formData).finally(() => {
      // 从活动 Promise 数组中移除这个 Promise
      const indexToRemove = activePromises.findIndex((p) => p === promise)
      if (indexToRemove !== -1) {
        activePromises.splice(indexToRemove, 1)
      }
      // 上传完成后，继续上传下一个分片
      uploadNext()
    })

    // 将这个 Promise 添加到活动 Promise 数组中
    activePromises.push(promise)

    // 如果活动 Promise 的数量超过了最大并发数，则等待一个 Promise 完成
    if (activePromises.length > MAX_REQUEST_NUM) {
      await Promise.race(activePromises.map((p) => p.finally(() => false))) // 使用 finally 确保不会因拒绝而停止
      // 注意：上面的 Promise.race 用法是为了等待任何一个 Promise 完成，但我们不关心它的结果（使用 false 作为占位符）
      // 实际上，由于我们在 finally 中已经处理了 Promise 的完成和移除，这里只需要等待即可
      // 更简单的做法可能是使用一个外部信号（如 Set 或类似结构）来跟踪哪些 Promise 已经完成，但这样会增加复杂性
    }

    // 增加分片索引以准备下一次上传
    index++
    process = ((index / formDatas.length) * 100).toFixed(2)
    console.log('进度:', process + '%')
  }

  // 开始上传过程
  uploadNext()
}
</script>
<template>
  <div>
    这是邹洪专用test
    <a-upload :custom-request="customRequest" :show-file-list="FALSE" />
  </div>
</template>
<style scoped></style>
